// Copyright (C) 2024 Kumo inc.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#pragma once

#include <ostream>
#include <krpc/rpc/restful_service.pb.h>
#include <krpc/kthread/fiber.h>
#include <krpc/rpc/restful_request.h>
#include <krpc/rpc/restful_response.h>
#include <turbo/container/flat_hash_map.h>
#include <turbo/utility/status.h>
#include <memory>

namespace krpc {
    struct RestfulProcessor {
        virtual ~RestfulProcessor() = default;

        virtual void process(const RestfulRequest *request, RestfulResponse *response) = 0;

        virtual bool is_wildcards() const = 0;
    };

    struct FunctionRestfulProcessor : public RestfulProcessor {
        FunctionRestfulProcessor(std::function<void(const RestfulRequest *, RestfulResponse *)> func, bool is_wildcards = false)
            : _func(std::move(func)), _is_wildcards(is_wildcards) {
        }

        void process(const RestfulRequest *request, RestfulResponse *response) override {
            _func(request, response);
        }

        bool is_wildcards() const override {
            return _is_wildcards;
        }

    private:
        std::function<void(const RestfulRequest *, RestfulResponse *)> _func;
        bool _is_wildcards;
    };

    class RestfulService : public restful_service {
    public:
        void default_method(::google::protobuf::RpcController *cntl_base,
                            const ::krpc::KMRestfulRequest *request,
                            ::krpc::KMRestfulResponse *response,
                            ::google::protobuf::Closure *done) override;

        void do_impl(::google::protobuf::RpcController *cntl_base,
                     const ::krpc::KMRestfulRequest *request,
                     ::krpc::KMRestfulResponse *response,
                     ::google::protobuf::Closure *done) override;

        RestfulService *set_not_found_processor(std::shared_ptr<RestfulProcessor> processor);

        RestfulService *set_any_path_processor(std::shared_ptr<RestfulProcessor> processor);

        RestfulService *set_root_processor(std::shared_ptr<RestfulProcessor> processor);

        RestfulService *set_processor(const std::string &path, std::shared_ptr<RestfulProcessor> processor);

        RestfulService *set_processor(const std::string &path, std::function<void(const RestfulRequest *, RestfulResponse *)> func,
                                      bool is_wildcards = false);

        RestfulService *set_mapping_path(const std::string &mapping_path);

        static RestfulService *instance() {
            static RestfulService service;
            return &service;
        }

    private:

        RestfulService();

        turbo::Status register_server(Server *server);

        std::string make_mapping_string();

        friend class Server;

    private:
        bool registered_{false};
        std::string mapping_path_;
        // for root path
        std::shared_ptr<RestfulProcessor> root_processor_;
        // for any path
        std::shared_ptr<RestfulProcessor> any_path_processor_;
        // for not found
        std::shared_ptr<RestfulProcessor> not_found_processor_;
        turbo::flat_hash_map<std::string, std::shared_ptr<RestfulProcessor> > processors_;
    };
} // namespace krpc
